import path from 'path';
import fs from 'fs';
import * as util from '../util';
import cfg from './config';
import { send } from './help';
import { download, events as downloadTasks } from './download';

const onEvent = (...args) => send('bookInstall', ...args);
const bookStoreDir = () => path.join(cfg.dataDir, '数字教材');
const bookZipStoreDir = () => path.join(bookStoreDir(), 'zips');
const bookDataFile = () => path.join(bookZipStoreDir(), 'data.json');

let bookData;
const getBookData = () => {
  try {
    if (!bookData) {
      bookData = JSON.parse(fs.readFileSync(bookDataFile()));
    }
    const res = {};
    for (const key of Object.keys(bookData)) {
      const bookInfo = bookData[key];
      if (bookInfo && bookInfo.status) {
        res[key] = bookInfo;
      }
    }
    return res;
  } catch (error) {
    //
  }
  return bookData;
};

const saveBookData = (bookId, data) => {
  try {
    if (!bookData) {
      bookData = {};
    }
    if (data === null) {
      delete bookData[bookId];
    } else {
      bookData[bookId] = {
        ...bookData[bookId],
        ...data,
      };
    }
    fs.writeFileSync(bookDataFile(), JSON.stringify(bookData));
  } catch (error) {
    //
  }
};

const getBookInfo = ({ bookId, bookExe }) => {
  const storeDir = bookStoreDir();
  const zipdir = bookZipStoreDir();
  const bookZip = path.join(zipdir, `${bookId}.zip`);
  const bookDir = path.join(storeDir, bookId);
  const bookExePath = path.join(bookDir, bookExe);
  return { zipdir, bookZip, bookDir, bookExePath };
};

/**
 * 列表
 */
const bookList = () => Promise.resolve(getBookData());
/**
 * 安装
 * @param {*} param0
 * @param {*} dirInfo
 */
const bookInstall = (args, dirInfo) => {
  const { bookId, bookMd5, bookUrl, bookExe } = args;
  return cfg.getDataDir(dirInfo).then(() => {
    const { zipdir, bookZip, bookDir, bookExePath } = getBookInfo({ bookId, bookExe });
    util.mkdirSync(bookDir);
    util.mkdirSync(zipdir);
    const taskId = `${new Date().getTime()}`;
    const downArgs = {
      taskId,
      fileUrl: bookUrl,
      filePath: bookZip,
      fileMd5: bookMd5,
      threads: args.threads || 2,
      isLzma: 0,
      onEvent: (type, res) => {
        switch (type) {
          case 'error':
            onEvent('error', { taskId, ...args, ...res });
            break;
          case 'progress':
            onEvent('progress', { taskId, ...args, ...res });
            break;
          case 'downloaded':
            onEvent('downloaded', { taskId, ...args, ...res });
            break;
        }
      },
    };
    return download(downArgs)
      .then((res) => {
        const { fileSave, downStatus } = res;
        if (downStatus === 1) {
          util.renameSync(fileSave, bookZip);
          onEvent('replaced', { taskId, ...args, ...res });
        }
        saveBookData(bookId, { bookMd5, bookExe, date: new Date(), status: 0 });
      })
      .then(() => {
        util.killByPath(bookExePath);
      })
      .then(() => {
        /* const unzip = path.join(cfg.appPath, 'unzip.exe');
        return util.execPromise(`unzip.exe -o "${unzip}" -d ${bookDir}`); */
        const exe7z = path.join(cfg.dirs.appPath, '7za.exe');
        onEvent('unzip', args);
        return util.execPromise(`"${exe7z}" x -y "${bookZip}" -o"${bookDir}"`);
      })
      .then(() => {
        saveBookData(bookId, { status: 1 });
        onEvent('complete', { taskId, ...args, status: 1 });
      });
  });
};
const charCode0 = '0'.charCodeAt();
const charCodea = 'a'.charCodeAt();
const charCodeA = 'A'.charCodeAt();
const binToHex = (source, bIsUpper = false) => {
  const sourcelen = source.length;
  const dest = [];
  for (let i = 0; i < sourcelen; i++) {
    let cTemp = source[i];
    for (let j = 0; j < 2; j++) {
      let cCur = cTemp & 0x0f;
      if (cCur < 10) {
        cCur += charCode0;
      } else {
        cCur += (bIsUpper ? charCodeA : charCodea) - 10;
      }
      dest[2 * i + 1 - j] = String.fromCharCode(cCur);
      cTemp >>= 4;
    }
  }
  return dest.join('');
};

const stringToByte = (str) => {
  const bytes = new Array();
  let len, c;
  len = str.length;
  for (let i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    if (c >= 0x010000 && c <= 0x10ffff) {
      bytes.push(((c >> 18) & 0x07) | 0xf0);
      bytes.push(((c >> 12) & 0x3f) | 0x80);
      bytes.push(((c >> 6) & 0x3f) | 0x80);
      bytes.push((c & 0x3f) | 0x80);
    } else if (c >= 0x000800 && c <= 0x00ffff) {
      bytes.push(((c >> 12) & 0x0f) | 0xe0);
      bytes.push(((c >> 6) & 0x3f) | 0x80);
      bytes.push((c & 0x3f) | 0x80);
    } else if (c >= 0x000080 && c <= 0x0007ff) {
      bytes.push(((c >> 6) & 0x1f) | 0xc0);
      bytes.push((c & 0x3f) | 0x80);
    } else {
      bytes.push(c & 0xff);
    }
  }
  return bytes;
};

const runBook = (name, arg, exit, opts) => {
  console.log('打开教材，教材的安装地址', path.join(cfg.dirs.appPath, `数字教材管理_${name}`));
  console.log('name, arg, exit, opts ====> ', name, arg, exit, opts);
  const result = util
    .spawnDetached(path.join(cfg.dirs.appPath, `数字教材管理_${name}`), [arg], {
      onExit: (code) => {
        util.loger.info(`数字教材管理_${name} Exit`, code);
        if (exit) {
          exit(code);
        }
      },
      ...opts,
    })
    .then((result) => {
      // 处理成功返回
      util.loger.info('应用成功启动', result);
    })
    .catch((error) => {
      // 处理错误
      util.loger.error('应用启动失败', error);
    });
  console.log('result ====================> ', result);
  return result;
};

/**
 * 打开
 * @param {*} param0
 */
const bookOpen = ({ bookId, bookExe, userId, encrypted, operation = '' }) => {
  const { bookDir, bookExePath } = getBookInfo({ bookId, bookExe });
  if (!fs.existsSync(bookExePath)) return Promise.resolve(false);
  const args = stringToByte(
    `BookID=${bookId}
  BookReaderPath=${bookExePath}
  UID=${userId}
  BookDir=${bookDir}
  EncryptedPublishID=${encrypted}
  Operation=${operation}`
      .split(/\n/g)
      .join('\r\n'),
  );

  const charCodey = 'y'.charCodeAt();
  const res = [];
  for (let index = 0; index < args.length; index++) {
    const code = args[index];
    res.push(code ^ charCodey);
  }
  const encryptedArgs = binToHex(res);
  return runBook('everyone', encryptedArgs, (code) => {
    console.log('code=======================> ', code);
    if (code === 4) {
      runBook('admin', encryptedArgs, 0, { shell: true });
    }
  });
};

/**
 * 获取教材章节目录
 * @param {*} param0
 * @returns
 */
const bookChaptersGet = async ({ taskId, bookId }) => {
  return Promise.resolve().then(async () => {
    downloadTasks.emit(taskId);
    onEvent('bookChaptersGet', { taskId, bookId });
    return '';
  });
};

/**
 * 卸载
 * @param {*} param0
 */
const bookUninstall = ({ bookId, bookExe }) => {
  const { bookZip, bookDir, bookExePath } = getBookInfo({ bookId, bookExe });
  return Promise.resolve()
    .then(async () => {
      util.rmdirSync(bookZip);
      // fix wys
      const fixExe = `${bookDir}\\BookRead\\BookRead.exe`;
      if (fs.existsSync(fixExe)) {
        await util.killByPath(fixExe);
      }

      if (fs.existsSync(bookExePath)) {
        await util.killByPath(bookExePath);
      }
    })
    .then(() => {
      util.rmdirSync(bookDir);
    })
    .then(() => {
      return saveBookData(bookId, null);
    });
};

const bookDownloadCancel = async ({ taskId, bookId }) => {
  return Promise.resolve().then(async () => {
    downloadTasks.emit(taskId);
    onEvent('cancel', { taskId, bookId, status: 1 });
    return saveBookData(bookId, null);
  });
};

export default {
  bookList,
  bookInstall,
  bookOpen,
  bookChaptersGet,
  bookUninstall,
  bookDownloadCancel,
};
